#!/usr/bin/env python

import socket, threading, SocketServer
import random
import sys
from UserDict import UserDict
#from rules import Rules

RED, BLUE, YELLOW, GREEN, BLACK = range(5)
SKIP, REVERSE, BUYTWO, BUYFOUR = range(10, 14)
def isNone(x):
    return x == None
def isntNone(x):
    return x != None

class Card:
    def __init__(self, color, number):
        self.color = color
        self.number = number
    def __str__(self):
        return ('Red', 'Blue', 'Yellow', 'Green', 'Black'
                )[self.color] + ':' + (
            'Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven',
            'Eight', 'Nine', 'SKIP', 'REVERSE', '+2', '+4')[self.number]
    def valid(self):
        if self.color == BLACK:
            return self.number in (0, BUYFOUR)
        return self.color in range(BLACK) and self.number in range(BUYFOUR)
    def has_power(self):
        return self.number in range(10, 14)
    def is_wild(self):
        return self.color == BLACK
    #def serialized(self):
    #import json
    #    return json.JSONEncoder().encode({
    #            'color': self.color,
    #            'number': self.number
    #            })
    def match_color(self, color):
        return self.color == color
    def match_number(self, number):
        return self.number == number
    def match_color_or_number(self, card):
        return self.match_color(card.color) or self.match_number(card.number)

class Deck:
    def __init__(self):
        self.cards=[]
        self.add_deck()
    def deal(self):
        if len(self.cards) > 0:
            return self.cards.pop()
    def deal_cards(self, num):
        return [self.cards.pop() for i in range(num)]
    def shuffle(self):
        random.shuffle(self.cards)
    def add_deck(self):
        self.cards.extend(self.standard())
        self.shuffle()
    def standard(self):
        cards=[]
        for color in range(BLACK): # para cada cor
            for number in range(BUYFOUR): # cria as coloridas
                cards.append(Card(color, number))
		if number != 0: # repete todos menos o 0
		    cards.append(Card(color, number))
            cards.append(Card(BLACK, 0))  # mais um curinga (Black:Zero)
            cards.append(Card(BLACK, BUYFOUR)) # e um compra quatro
        return cards


class Player:
    def __init__(self, name):
        self.name = name
        self.cards=[]
    def add_card(self, card):
        self.cards.append(card)
    def add_cards(self, cards):
        self.cards.extend(cards)
    def has_card(card):
        return card in self.cards
    def __str__(self):
        return self.name + '=' + str([str(c) for c in self.cards])
    
class Jogada():
    def __init__(self, player, card, color=None):
        self.player = player
        self.card = card
        self.chosen_color = color

# essa classe implementa as regras do jogo
# uma versao alternativa do jogo pode ser feita
# fazendo alternativa a ela
class Rules():
    """Rules implementa as regras originais do Uno
    """
    def valid_move(self, game, play):
        top_card = game.top_card
        if play.player != game.cur_player:
            return False
	if play.card == None:	# carta nula eh pedido de compra
	    return True
        if top_card.color == BLACK:
            if play.card.color == game.chosen_color:
                return True
        if play.card.match_color_or_number(top_card):
            return True
        return False
    def apply_power(self, game, power):
	if power == SKIP:
	    game.next_player()
	elif power == REVERSE:
	    game.players.reverse()
	elif power == BUYTWO:
	    game.next_player()
	    game.cur_player.add_cards(game.deck.deal_cards(2))
	elif power == BUYFOUR:
	    game.next_player()
	    game.cur_player.add_cards(game.deck.deal_cards(4))
    def apply(self, game, play):
        if self.valid_move(game, play):
            # se for jogada valida, aplica alguma regra especial,
            # e passa a vez para o proximo jogador
            if len(play.player.cards) == 0:
                print str(play.player.name) + ' venceu!'
                return
	    if play.card == None:
		play.card = game.deck.deal()
		if not self.valid_move(game, play):
		    play.player.add_card(play.card)
		    return
            if len(play.player.cards) == 1:
                print str(play.player.name) + ' UNOed!'
	    if play.card.has_power():
		self.apply_power(game, play.card.number)
            if play.card.is_wild():
                game.chosen_color=play['chosen_color']
	    game.top_card=play.card
            game.next_player()
        else:
            # penalidade pra quem jogar errado eh comprar duas
            play.player.add_cards(game.deck.deal_cards(2))
            print play.player.name + ' tentou jogar ' + str(play.card)

class Game:
    def __init__(self):
        self.players=[]
        self.deck=Deck()
        self.top_card=None
        self.cur_player=None
        self.rules=Rules()
        self.chosen_color=None
    def init(self, num_players):
        for i in range(num_players):
            self.new_player()
    def new_player(self, player_name=None, num_cards=7):
	if player_name == None:
	    player_name = 'Player' + str(len(self.players)+1)
        p = Player(player_name)
        p.add_cards([self.deck.deal() for i in range(num_cards)])
        self.players.append(p)
	return p
    def play(self, play):
        self.rules.apply(self, play)
    def next_player(self, player=None):
        if isNone(player): player = self.cur_player
        if isNone(player) or player == self.players[-1]:
            self.cur_player=self.players[0]
        else:
            self.cur_player=self.players[self.players.index(player) + 1]
    def start(self):
        # testando o treco com 3 jogadores
        self.init(3)
        self.top_card=self.deck.deal()
        self.next_player()
        print str(self.players[0])
        print str(self.players[1])
        print str(self.players[2])


HOST, PORT = "localhost", 15250

# TODO: corrigir essa naba
class Servidor(SocketServer.StreamRequestHandler):
    def processa(self):
	print 'aqui processa a logica'
    def feedback(self, data):
	self.rfile.write(data['response'])
    def handle(self):
        data = self.rfile.readline().strip()
	if data == 'init_client':
	    print 'recebi: ' + data + ' de: ' + str(self.client_address[0])
	    new_player = game.new_player()
	    response = "'%s' recebido:%s" % (data.upper(), new_player.name)
	elif data.startswith('jogada:'):
	    # TODO: implementar essa naba
	    #game.play(Jogada())
	    response = 'JOGADA RECEBIDA'
	else:
	    response = 'non te conheco'
	print 'jogadores: ' + str(len(game.players))
	self.feedback({'response': response})
    def main(self):
	self.server = SocketServer.TCPServer((HOST, PORT), self)
	ip, port = self.server.server_address
	game.new_player('PlayerServidor')
	print 'Iniciando servidor...'
	self.server.serve_forever()

class Cliente:
    def main(self, ip, port):
	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	sock.connect((ip, port))
	sock.send("init_client\n")
	response = sock.recv(1024)
	print "Received: '%s'" % response
	sock.send("jogada:\n")
	response = sock.recv(1024)
	print "Received: '%s'" % response
	sock.close()

if __name__ == '__main__':
    if len(sys.argv) > 1 and sys.argv[1] == 'server':
	servidor = Servidor((HOST, PORT))
	game = Game()
	servidor.main()
    else:
	Cliente().main(HOST, PORT)
